﻿namespace NetFx.MSIL
{
  using System;
  using System.Text;

  using System.Reflection;
  using System.Reflection.Emit;

  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;
  using NetFx.Utils;

  public class ILCodeWriter
  {
    #region Statics
    public static ILCodeWriter of(ILGenerator g)
    {
      return new ILCodeWriter(g);
    }
    #endregion
    #region Fields
    protected ILGenerator builder;
    #endregion
    #region Properties
    public virtual ILGenerator Builder
    {
      get
      {
        return this.builder;
      }
    }
    #endregion
    #region Constructors
    public ILCodeWriter(ILGenerator generator)
    {
      if (generator == null) throw new ArgumentNullException("g can not be null!");
      this.builder = generator;
    }
    #endregion
    #region Methods
    #region Exception blocks
    public virtual void OpenCatchBlock(Type expressionType)
    {
      this.Builder.BeginCatchBlock(expressionType);
    }
    public virtual void OpenExceptionFilterBlock()
    {
      this.Builder.BeginExceptFilterBlock();
    }
    public virtual Label OpenExceptionBlock()
    {
      return this.Builder.BeginExceptionBlock();
    }
    public virtual void OpenFaultBlock()
    {
      this.Builder.BeginFaultBlock();
    }
    public virtual void OpenFinallyBlock()
    {
      this.Builder.BeginFinallyBlock();
    }
    public virtual void CloseExceptionBlock()
    {
      this.Builder.EndExceptionBlock();
    }
    public virtual void ThrowException(Type exceptionType)
    {
      this.Builder.ThrowException(exceptionType);
    }
    #endregion
    #region Scopes and Namespaces
    public virtual void OpenScope()
    {
      this.Builder.BeginScope();
    }
    public virtual void CloseScope()
    {
      this.Builder.EndScope();
    }
    public virtual void DefineUsingNamespace(string usingNamespace)
    {
      this.Builder.UsingNamespace(usingNamespace);
    }
    #endregion
    #region Locals
    public virtual LocalBuilder WriteLocalDeclaration(Type localType)
    {
      return this.Builder.DeclareLocal(localType);
    }
    public virtual LocalBuilder WriteLoaclDeclaration(Type localType, bool pinned)
    {
      return this.Builder.DeclareLocal(localType, pinned);
    }
    #endregion
    #region Labels and positions
    public virtual Label WriteLabelDeclaration()
    {
      return this.Builder.DefineLabel();
    }
    public virtual void WriteLabel(Label label)
    {
      this.Builder.MarkLabel(label);
    }
    public virtual void WritePositionMark(ISymbolDocumentWriter docWriter, Location startLocation, Location endLocation)
    {
      this.Builder.MarkSequencePoint(docWriter, startLocation.Row, startLocation.Column, endLocation.Row, endLocation.Column);
    }
    #endregion
    #region Codes
    #region Generate WriteLine
    public virtual void OutpuWriteLine(string value)
    {
      this.Builder.EmitWriteLine(value);
    }
    public virtual void OutpuWriteLine(FieldInfo field)
    {
      this.Builder.EmitWriteLine(field);
    }
    public virtual void OutpuWriteLine(LocalBuilder local)
    {
      this.Builder.EmitWriteLine(local);
    }
    #endregion
    #region Emits
    public virtual void Write(OpCode code)
    {
      this.Builder.Emit(code);
    }
    public virtual void Write(OpCode code, byte arg)
    {
      this.Builder.Emit(code,arg);
    }
    public virtual void Write(OpCode code, int arg)
    {
      this.Builder.Emit(code, arg);
    }
    public virtual void Write(OpCode code, float arg)
    {
      this.Builder.Emit(code, arg);
    }
    public virtual void Write(OpCode code, long arg)
    {
      this.Builder.Emit(code, arg);
    }
    public virtual void Write(OpCode code, double arg)
    {
      this.Builder.Emit(code, arg);
    }
    public virtual void Write(OpCode code, sbyte arg)
    {
      this.Builder.Emit(code, arg);
    }
    public virtual void Write(OpCode code, short arg)
    {
      this.Builder.Emit(code, arg);
    }
    public virtual void Write(OpCode code, string arg)
    {
      this.Builder.Emit(code, arg);
    }
    public virtual void Write(OpCode code, Type arg)
    {
      this.Builder.Emit(code,arg);
    }
    public virtual void Write(OpCode code, ConstructorInfo constructorInfo)
    {
      this.Builder.Emit(code, constructorInfo);
    }
    public virtual void Write(OpCode code, FieldInfo fieldInfo)
    {
      this.Builder.Emit(code, fieldInfo);
    }
    public virtual void Write(OpCode code, MethodInfo methodInfo)
    {
      this.Builder.Emit(code, methodInfo);
    }
    public virtual void Write(OpCode code, LocalBuilder local)
    {
      this.Builder.Emit(code, local);
    }
    public virtual void Write(OpCode code, Label label)
    {
      this.Builder.Emit(code, label);
    }
    public virtual void Write(OpCode code, Label[] labels)
    {
      this.Builder.Emit(code, labels);
    }
    public virtual void Write(OpCode code, SignatureHelper signature)
    {
      this.Builder.Emit(code, signature);
    }
    #endregion
    #endregion
    #endregion
  }
}
